package businessCommonQuery

import (
	"fmt"
	"grpc.getaway.adminspro.padmins.com/pkg/config/businessError"
	"grpc.getaway.adminspro.padmins.com/pkg/libs/utils"
	pbCommon "grpc.getaway.adminspro.padmins.com/pkg/proto/common"
	"regexp"
	"strings"
)

const db_field_pattern = "(^_([a-zA-Z0-9.]_?)*$)|(^[a-zA-Z](_?[a-zA-Z0-9.])*_?$)"

type where string
type bindValue []interface{}
type limit string
type order string

func BuildByBusinessCommonQuery(q *pbCommon.BusinessCommonQuery) (where, bindValue, limit, order, *businessError.ErrorInfo) {
	if q == nil {
		return "", nil, "", "", nil
	}

	wheres := map[string][]interface{}{}

	for key, param := range q.Filters {
		matched, e := regexp.MatchString(db_field_pattern, key)
		if e != nil {
			return "", nil, "", "", businessError.Error(businessError.ParamsInvalid.Code, e.Error())
		}

		if matched != true {
			return "", nil, "", "", businessError.Error(businessError.ParamsInvalid.Code, fmt.Sprintf("invalid param filter[%s]", key))
		}

		op := "="
		if _, ok := q.Ops[key]; ok {
			op = q.Ops[key]
		}

		switch strings.ToUpper(op) {
		case "=", "<>", "!=", ">", ">=", "<", "<=", "LIKE", "NOT LIKE":
			wheres[fmt.Sprintf("%s %s ?", key, op)] = []interface{}{param}
		case "RANGE", "NOT RANGE", "BETWEEN", "NOT BETWEEN":
			op = strings.ReplaceAll(op, "RANGE", "BETWEEN")
			params := make([]interface{}, 2)
			if strings.Index(param, ",") == -1 {
				for k, v := range strings.Split(strings.TrimSpace(param), " - ") {
					params[k] = v
					if k == 1 {
						break
					}
				}
			} else {
				for k, v := range strings.Split(strings.TrimSpace(param), ",") {
					params[k] = v
					if k == 1 {
						break
					}
				}
			}

			if len(params) < 2 {
				params[1] = ""
			}

			if params[0] == "" {
				if op == "BETWEEN" {
					op = "<="
				} else {
					op = ">"
				}
				wheres[fmt.Sprintf("%s %s ?", key, op)] = []interface{}{params[1]}
			} else if params[1] == "" {
				if op == "BETWEEN" {
					op = ">="
				} else {
					op = "<"
				}
				wheres[fmt.Sprintf("%s %s ?", key, op)] = []interface{}{params[0]}
			} else {
				wheres[fmt.Sprintf("%s %s ? AND ?", key, op)] = params
			}

		case "IN", "NOT IN":
			vv := []interface{}{}
			for _, v := range strings.Split(param, ",") {
				vv = append(vv, v)
			}
			wheres[fmt.Sprintf("%s %s (?)", key, op)] = []interface{}{vv}
		default:
			return "", nil, "", "", businessError.Error(businessError.ParamsInvalid.Code, fmt.Sprintf("invalid param ops[%s]", op))
		}
	}

	andWhere := []string{}
	aBindValue := []interface{}{}

	for whes, params := range wheres {
		andWhere = append(andWhere, whes)
		aBindValue = append(aBindValue, params...)
	}
	w := ""
	if len(andWhere) > 0 {
		w = " AND " + utils.Implode(" AND ", andWhere)
	}

	sLimit := ""
	if q.Limit > 0 {

		if q.Offset < 0 {
			return "", nil, "", "", businessError.Error(businessError.ParamsInvalid.Code, "offset参数错误")
		}

		if q.Limit > 0 {
			sLimit = fmt.Sprintf("limit %d,%d", q.Offset, q.Limit)
		} else {
			sLimit = ""
		}
	} else {
		sLimit = ""
	}

	sOrder := ""
	if len(q.Sort) > 0 {
		for _, sort := range q.Sort {
			aSort := strings.Split(sort, "-")
			sortField := ""
			orderWay := "ASC"
			sortField = aSort[0]
			if len(aSort) > 1 {
				orderWay = aSort[1]
			}

			matched, e := regexp.MatchString(db_field_pattern, sortField)
			if e != nil {
				return "", nil, "", "", businessError.Error(businessError.ParamsInvalid.Code, e.Error())
			}

			if matched != true {
				return "", nil, "", "", businessError.Error(businessError.ParamsInvalid.Code, fmt.Sprintf("invalid param sort[%s]", sortField))
			}

			orderWay = strings.ToUpper(orderWay)
			if orderWay != "ASC" && orderWay != "DESC" {
				return "", nil, "", "", businessError.Error(businessError.ParamsInvalid.Code, fmt.Sprintf("invalid param sort[%s] order[%s]", sortField, orderWay))
			}

			sOrder += fmt.Sprintf("%s %s,", sortField, orderWay)
		}
		sOrder = "order by " + strings.Trim(sOrder, ",")
	}

	return where(strings.TrimSpace(w)), bindValue(aBindValue), limit(sLimit), order(sOrder), nil
}
